<?php
/**
 * Hoffman Framework
 *
 * LICENSE
 *
 * This source file is subject to the GNU LGPL 2.1 license that is bundled
 * with this package in the file license.txt.
 * It is also available through the world-wide-web at this URL:
 * http://creativecommons.org/licenses/LGPL/2.1
 * If you did not receive a copy of the license and are unable to
 * obtain it through the world-wide-web, please send an email
 * to annop@thaicyberpoint.com so we can send you a copy immediately.
 *
 * @package    Hoffman
 * @author     Ford AntiTrust
 * @copyright  Copyright (c) 2008 Ford AntiTrust (http://www.thaicyberpoint.com/ford/blog)
 * @since      Version Rv 0.2
 * @license    http://creativecommons.org/licenses/LGPL/2.1
 *             GNU LGPL 2.1
 * @filesource
 */

if (!defined('INDEX'))
    die('No direct script access allowed.');

/**
 * @see Zend_Registry
 */
require_once 'Zend/Registry.php';

/**
 * @see Hmf_View_Buffer
 */
require_once 'Hmf/View/Buffer.php';

/**
 * @see Hmf_Errors
 */
require_once 'Hmf/Errors.php';

/**
 * @see Hmf_Logs
 */
require_once 'Hmf/Logs.php';

/**
 * View
 *
 * @package     Hoffman
 * @subpackage  Hmf
 * @category    View
 * @author      Ford AntiTrust
 * @version     SVN: $Id: View.php 152 2009-06-08 07:32:15Z annop.s@gmail.com $
 * @link        http://www.thaicyberpoint.com/ford/blog/hmf
 */

class Hmf_View extends Hmf {

    const masterPageStickyReserveKeys = 'charset|meta|base_url|webhost|title|headlinks|stylesheets|javascripts';

    const contentPageStickyReserveKeys = 'index';

    private $contentPage = array();

    private $masterPage;

    private $masterPageSticky = array();

    private $contentPageSticky = array();

    private $javascripts = array();

    private $stylesheets = array();

    private $headlink = array();

    private $feed = array();

    private $title = null;

    public static $cache;

    function __construct() {

        $app_viewinfo = Zend_Registry::get('app_viewinfo');

        if (count($app_viewinfo['javascripts']) > 0)
            foreach ($app_viewinfo['javascripts'] as $javascriptName)
                self::addJavaScript($javascriptName);

        if (count($app_viewinfo['stylesheets']) > 0)
            foreach ($app_viewinfo['stylesheets'] as $stylesheetName)
                self::addStyleSheet($stylesheetName);

        $this->masterPage = array();
        $this->contentPage['index'] = array();
        $this->contentPageSticky['index'] = array();
    }

    public function createContentPage($stickyKey) {

        if (!in_array($stickyKey, explode('|', self::contentPageStickyReserveKeys))) {
            $this->contentPage[$stickyKey] = array();
            $this->contentPageSticky[$stickyKey] = array();
            return true;
        }

        Hmf_Logs::sendWarningToLog("You didn't use the '$stickyKey' for create the Content-page to the Master-page, it's reserve Sticky-key (" . self::contentPageStickyReserveKeys . ") for the Content-page.");
        return false;
    }

    public function setTitle($val) {

        $this->title = $val;
    }

    public function getTitle() {

        $app_config = Zend_Registry::get('app_config');

        if (is_null($this->title)) {
            return $app_config['title'];
        } else {
            return $this->title;
        }
    }

    public function addFeed($url, $title = null, $type = 'application/rss+xml') {

        $app_config = Zend_Registry::get('app_config');

        if (!is_null($url)) {
            if (is_null($title)) {
                $title = $app_config['title'];
            }
            self::addHeadLink(array('rel' => 'alternate', 'type' => $type, 'title' => $title, 'href' => $url));
        }
    }

    public function addHeadLink($attributes) {

        $this->headlink[ ] = $attributes;
    }

    public function getHeadLink() {

        $out = null;
        if (count($this->headlink) > 0) {
            foreach ($this->headlink as $headlinkData) {
                $out .= '<link' . self::attributes($headlinkData) . " />\n";
            }
            return $out;
        } else {
            return null;
        }
    }

    public function addJavaScript($file, array $options = array()) {

        $this->javascripts[ ] = array('file' => $file, 'options' => $options);
    }

    public function getJavaScript() {

        $app_config = Zend_Registry::get('app_config');

        $out = null;
        if (count($this->javascripts) > 0) {
            foreach ($this->javascripts as $javascriptsData) {
                /* Begin check 'file' is outside from this app. */
                if (preg_match('@((ht|f)tps?://([-\w\.]+)+(:\d+)?(/([\w/_\.]*(\?\S+)?)?)?)|(^\/)@', $javascriptsData['file']) > 0)
                    $path = $javascriptsData['file'];
                else
                    $path = $app_config['base_url'] . '/javascripts/' . $javascriptsData['file'] . '.js';
                $out .= '<script type="text/javascript"' . self::attributes($javascriptsData['options']) . ' src="' . $path . '"></script>' . "\r\n";
            }
            return $out;
        } else {
            return null;
        }
    }

    public function addStyleSheet($file, $media = 'all') {

        $this->stylesheets[ ] = array('file' => $file, 'media' => $media);
    }

    public function getStyleSheet() {

        $app_config = Zend_Registry::get('app_config');

        $out = null;
        if (count($this->stylesheets) > 0) {
            foreach ($this->stylesheets as $stylesheetsData) {
                /* Begin check 'file' is outside from this app. */
                if (preg_match('@((ht|f)tps?://([-\w\.]+)+(:\d+)?(/([\w/_\.]*(\?\S+)?)?)?)|(^\/)@', $stylesheetsData['file']) > 0)
                    $path = $stylesheetsData['file'];
                else
                    $path = $app_config['base_url'] . '/stylesheets/' . $stylesheetsData['file'] . '.css';
                $out .= '<style type="text/css" media="' . $stylesheetsData['media'] . '">@import "' . $path . '";</style>' . "\n";
                //$out .= '<link rel="stylesheet" type="text/css" href="' . $path . '" '.self::attributes($stylesheetsData ['options']).' />' . "\r\n";
            }
            return $out;
        } else {
            return null;
        }
    }

    private function setConfigTo($type, $var, $val, $stickyKey = 'index') {

        if (!in_array($type, array('masterPage', 'contentPage'))) {
            $type = 'contentPage';
        }
        if ($type == "contentPage") {
            $this->{$type}[$stickyKey][$var] = $val;
        } else {
            $this->{$type}[$var] = $val;
        }
    }

    private function getConfigFrom($type, $var, $stickyKey = 'index') {

        if (!in_array($type, array('masterPage', 'contentPage'))) {
            $type = 'contentPage';
        }
        if ($type == "contentPage") {
            return $this->{$type}[$stickyKey][$var];
        } else {
            return $this->{$type}[$var];
        }
    }

    private function sendDataTo($type, $data, $stickyKey = 'index') {

        if (!in_array($type, array('masterPage', 'contentPage'))) {
            $type = 'contentPage';
        }
        if (is_array($data)) {
            if ($type == "contentPage") {
                foreach ($data as $key => $val) {
                    $this->{$type}[$stickyKey]['data'][$key] = $val;
                }
            } else {
                foreach ($data as $key => $val) {
                    $this->{$type}['data'][$key] = $val;
                }
            }
        } else {
            if ($type == "contentPage") {
                $this->{$type}[$stickyKey]['data']['data'] = $data;
            } else {
                $this->{$type}['data']['data'] = $data;
            }
        }
    }

    private function setContentPageConfig($stickyKey, $var, $val) {

        $this->setConfigTo('contentPage', $var, $val, $stickyKey);
    }

    private function setMasterPageConfig($var, $val) {

        $this->setConfigTo('masterPage', $var, $val);
    }

    private function getMasterPageConfig($var) {

        $this->getConfigFrom('masterPage', $var);
    }

    private function getContentPageConfig($stickyKey, $var) {

        $this->getConfigFrom('contentPage', $var, $stickyKey);
    }

    private function sendDataToContentPage($data, $stickyKey = 'index') {

        $this->sendDataTo('contentPage', $data, $stickyKey);
    }

    private function sendDataToMasterPage($data) {

        $this->sendDataTo('masterPage', $data);
    }

    public function appendMasterPageData(array $data) {

        if (is_array($data) and !self::arrayKeyExistsFindbyArray(explode('|', self::masterPageStickyReserveKeys), $data)) {

            $this->masterPageSticky = array_merge($this->masterPageSticky, $data);
        } else {

            Hmf_Logs::sendWarningToLog("You didn't use the reserve key for append data to the Masterpage, it's a reserve key (" . Hmf_View::masterPageStickyReserveKeys . ") for the Masterpage.");
        }
    }

    public function appendContentPageData($stickyKey, $data) {

        if (is_array($data)) {
            $this->contentPageSticky[$stickyKey] = array_merge($this->contentPageSticky[$stickyKey], $data);
        } else {
            $this->contentPageSticky[$stickyKey] = $data;
        }
    }

    private function fetchDataFromContentPage($pathContentPage, $stickyKey = 'index') {

        return $this->fetchDataFrom('contentPage', $pathContentPage, $stickyKey);
    }

    private function fetchDataFromMasterPage($pathMasterPage) {

        return $this->fetchDataFrom('masterPage', $pathMasterPage);
    }

    private function fetchDataFrom($type, $pathContentPage, $stickyKey = 'index') {

        $type = (!in_array($type, array('masterPage', 'contentPage'))) ? 'contentPage' : $type;

        if (strcmp($type, "contentPage") == 0) {
            $var = & $this->{$type}[$stickyKey]['data'];
        } else {
            $var = & $this->{$type}['data'];
        }

        return new Hmf_View_Buffer($pathContentPage, $var);
    }

    final public static function useMasterPageCache($type = true, $lifetime = 300) {

        self::$cache['masterPage'] = array('type' => $type, 'lifetime' => $lifetime);

        return $this;
    }

    final public static function useContentPageCache($stickyKey = 'index', $type = true, $lifetime = 300) {

        self::$cache['contentPage'][$stickyKey] = array('type' => $type, 'lifetime' => $lifetime);

        return $this;
    }

    public function renderPreMasterPageSticky() {

        $app_viewinfo = Zend_Registry::get('app_viewinfo');

        $app_config = Zend_Registry::get('app_config');

        $this->masterPageSticky['charset'] = & $app_viewinfo['charset'];
        $this->masterPageSticky['meta'] = & $app_viewinfo['meta'];
        $this->masterPageSticky['base_url'] = & $app_config['base_url'];
        $this->masterPageSticky['webhost'] = & $app_config['webhost'];
        $this->masterPageSticky['headlinks'] = $this->getHeadLink();
        $this->masterPageSticky['stylesheets'] = $this->getStyleSheet();
        $this->masterPageSticky['javascripts'] = $this->getJavaScript();

    }
    public function render($objController) {

        $app_config = Zend_Registry::get('app_config');

        $app_cache = Zend_Registry::get('app_cache');

        $pathMasterPage = PATH_DIR_APPLICATION_VIEWS_MASTERPAGES . '/' . $objController->getUseMasterPage() . '.php';

        if (!file_exists($pathMasterPage)) {
            Hmf_Errors::missingMasterpageFile(end(explode('/', $pathMasterPage)));
        }
        if ($app_config['cache.view.head']) {
            $masterPageStickyCacheId = 'masterpage_sticky_'.Zend_Registry::get('controller_name').'_'.Zend_Registry::get('action_name');
            if (!($this->masterPageSticky = $app_cache->load($masterPageStickyCacheId))) {
                $this->renderPreMasterPageSticky();
                if(Zend_Registry::get('is_production')) {
                    $app_cache->save($this->masterPageSticky, $masterPageStickyCacheId);
                }
            }
        } else {
            $this->renderPreMasterPageSticky();
        }

        $this->masterPageSticky['title'] = $this->getTitle();
        /*
         * ส่งข้อมูลที่ได้จากกระบวนการของ Controller และ Register พวก function ต่าง ๆ ส่งให้กับ Content-page
         */
        $contentPageStickyKeys = array_keys($this->contentPageSticky);
        foreach ($contentPageStickyKeys as $stickyKey) {

            $pathContentPage = PATH_DIR_APPLICATION_VIEWS_CONTENTPAGES . '/' . $objController->getUseContentPage($stickyKey) . '.php';

            if (!file_exists($pathContentPage)) {
                Hmf_Errors::missingContentpageFile($stickyKey);
            }

            $this->sendDataToContentPage($this->contentPageSticky[$stickyKey], $stickyKey);
            $this->masterPageSticky['contentpage'][$stickyKey] = $this->fetchDataFromContentPage($pathContentPage, $stickyKey);

        }

        /*
         * Render ข้อมูลของ Content-page มาใส่ใน Sticky ชื่อ contentpage ของ Master-page
         */
        $this->sendDataToMasterPage($this->masterPageSticky);

        echo $this->fetchDataFromMasterPage($pathMasterPage);
    }

    /**
     * Format an attribute string to insert in a tag.
     *
     * @param array $attributes An associative array of HTML attributes.
     * @return string (An HTML string ready for insertion in a tag.)
     */

    public static function attributes(array $attributes = array()) {

        if (is_array($attributes)) {
            $txt = null;
            foreach ($attributes as $key => $val) {
                $txt .= " $key=" . '"' . self::checkPlain($val) . '"';
            }
            return $txt;
        }
        return null;
    }

    /**
     * Encode special characters in a plain-text string for display as HTML.
     *
     * @param string $text
     * @return string
     *
     * code from Drupal
     * check_plain($text)
     * includes/bootstrap.inc, line 680
     */
    public static function checkPlain($text) {

        return self::validateUtf8($text) ? htmlspecialchars($text, ENT_QUOTES) : '';
    }

    /**
     * Check if a String contains valid utf-8
     *
     * @param string $text
     * @return boolean (TRUE if the text is valid UTF-8, FALSE if not.)
     *
     * code from Drupal
     * drupal_validate_utf8($text)
     * includes/bootstrap.inc, line 713
     */
    public static function validateUtf8($text) {

        if (mb_strlen($text) == 0) {
            return TRUE;
        }
        return (preg_match('/^./us', $text) == 1);
    }

    /**
     * Checks if the given key or index exists from source array in the destination array
     *
     * @param array $array_needle
     * @param array $array_haystack
     * @return boolean (TRUE if the array_needle is finded, FALSE if not.)
     */
    function arrayKeyExistsFindbyArray($array_needle, $array_haystack) {

        foreach ($array_needle as $needle_key)
            if (array_key_exists($needle_key, $array_haystack))
                return true;
        return false;
    }
}
?>